package reporte.filtros;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;

import clientes.Ticket;
import reporte.filtros.Filtro;
import productosYPresentaciones.Producto;
import ventas.Venta;

/**
 * Clase generica de filtros de ventas
 * @author Octavio Nicolas Pompilio
 *
 */
public abstract class FiltroVentaTest {

	public Venta venta1,venta2,venta3,venta4,venta5;
	public List<Venta> lista;
	public DateTime fechabase;
	public Producto productoABuscar, productoSolitario;
	private Filtro<Venta> filtro;
	
	/**
	 * Crea todos los elementos para realizar el test
	 * @throws Exception
	 */
	@Before
	public void setUp() throws Exception {
		lista = new ArrayList<Venta>();
		venta1 = mock( Venta.class );
		venta2 = mock( Venta.class );
		venta3 = mock( Venta.class );
		venta4 = mock( Venta.class );
		venta5 = mock( Venta.class );
		
		lista.add(venta1);
		lista.add(venta2);
		lista.add(venta3);
		lista.add(venta4);
		lista.add(venta5);
		
		//Fundamental para hacer funcionar los test
		this.inicializarFechas();
		this.inicializarMontos();
		this.inicializarProductos();
		this.inicializarVentasPendientes();
	}

	protected void inicializarVentasPendientes() {
		//Se establecen si son ventas con envio
		when( venta1.soyUnaVentaConEnvio() ).thenReturn(true);
		when( venta2.soyUnaVentaConEnvio() ).thenReturn(false);
		when( venta3.soyUnaVentaConEnvio() ).thenReturn(false);
		when( venta4.soyUnaVentaConEnvio() ).thenReturn(true);
		when( venta5.soyUnaVentaConEnvio() ).thenReturn(false);
	}
	
	/**
	 * Se crean todos los datos necesarios para realizar test con fechas
	 */
	protected void inicializarFechas(){
		//Fechas de las ventas
		fechabase =  new DateTime();
		DateTime fechav1 = fechabase.plusMonths(1),
				fechav2 = fechabase.plusMonths(2),
				fechav3 = fechabase.plusMonths(3),
				fechav4 = fechabase.plusMonths(5),
				fechav5 = fechabase.plusMonths(10);
		//Basicamente estan ordenadas cronologicamente

		//Se establecen las fechas de las ventas
		when( venta1.getFechaDeCreacionDeLaVenta() ).thenReturn(fechav1);
		when( venta2.getFechaDeCreacionDeLaVenta() ).thenReturn(fechav2);
		when( venta3.getFechaDeCreacionDeLaVenta() ).thenReturn(fechav3);
		when( venta4.getFechaDeCreacionDeLaVenta() ).thenReturn(fechav4);
		when( venta5.getFechaDeCreacionDeLaVenta() ).thenReturn(fechav5);
	}
	
	/**
	 * Se crean todos los datos necesarios para realizar test con montos
	 */
	protected void inicializarMontos(){
		//Tickets(para montos) de las ventas
		Ticket rc1 = mock(Ticket.class),
				rc2 = mock(Ticket.class),
				rc3 = mock(Ticket.class),
				rc4 = mock(Ticket.class),
				rc5 = mock(Ticket.class);
		

		//Se establecen los montos de las ventas
		when( venta1.getTicketDeVenta() ).thenReturn(rc1);
		when( venta2.getTicketDeVenta() ).thenReturn(rc2);
		when( venta3.getTicketDeVenta() ).thenReturn(rc3);
		when( venta4.getTicketDeVenta() ).thenReturn(rc4);
		when( venta5.getTicketDeVenta() ).thenReturn(rc5);
		when(rc1.getPrecio()).thenReturn(500f);
		when(rc2.getPrecio()).thenReturn(40f);
		when(rc3.getPrecio()).thenReturn(2000f);
		when(rc4.getPrecio()).thenReturn(5f);
		when(rc5.getPrecio()).thenReturn(125f);
	}
	
	/**
	 * Se crean todos los datos necesarios para realizar test con productos
	 */
	protected void inicializarProductos(){
		//Se establecen los productos participantes del test
		productoABuscar = mock( Producto.class );
		productoSolitario = mock( Producto.class );
		
		//Se establecen la listas de productos 
		Map<Producto,Integer> listaConProductoABuscar = mock( Map.class ),
				listaConProductoSolitario = mock( Map.class ),
				listaConAmbosProductos = mock( Map.class );

		//Que productos contiene cada lista de productos
		when( listaConProductoABuscar.containsKey(productoABuscar) ).thenReturn(true);
		when( listaConProductoABuscar.containsKey(productoSolitario) ).thenReturn(false);
		when( listaConProductoSolitario.containsKey(productoABuscar) ).thenReturn(false);
		when( listaConProductoSolitario.containsKey(productoSolitario) ).thenReturn(true);
		when( listaConAmbosProductos.containsKey(productoABuscar) ).thenReturn(true);
		when( listaConAmbosProductos.containsKey(productoSolitario) ).thenReturn(true);


		//Se establecen las listas de compras de las ventas
		when( venta1.getProductosComprados() ).thenReturn( listaConProductoABuscar );
		when( venta2.getProductosComprados() ).thenReturn( listaConAmbosProductos );
		when( venta3.getProductosComprados() ).thenReturn( listaConProductoSolitario );
		when( venta4.getProductosComprados() ).thenReturn( listaConProductoSolitario );
		when( venta5.getProductosComprados() ).thenReturn( listaConAmbosProductos );
	}

	/**
	 * Setea el filtro que se testea
	 * @param filtro
	 * El elemento a testear
	 */
	public void setSUT(Filtro<Venta> filtro){
		this.filtro = filtro;
	}
	
	/**
	 * Devuelve el filtro a testear
	 * @return
	 * Un filtro
	 */
	public Filtro<Venta> getSUT(){
		return this.filtro;
	}
	
	/**
	 * Testea la funcionalidad del filtro.
	 */
	@Test
	public abstract void testDelFiltro();
	
	/**
	 * Testea las condiciones del criterio del
	 * filtro
	 */
	@Test
	public abstract void testDeLaCondicion();
	
	/**
	 * Testea que no deberia haber resultados
	 * cuando no hay elementos
	 */
	@Test
	public void testSucursalesSinProductosDanReportesVacios() {
		assertTrue( getSUT().filtrar(new ArrayList<Venta>()).isEmpty() );
	}
}
